package com.quectel.cms.controller.sys;

import com.quectel.business.common.thirdconfig.ThirdPlatformConfigBusiness;
import com.quectel.cms.constants.CmsRedisCacheConstants;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.interceptor.LoginUserSession;
import com.quectel.cms.service.sys.ApiSysLoginService;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.sys.offcialaccounts.JSAPILoginVo;
import com.quectel.constant.core.officialaccount.OfficialAccountsConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.officialaccounts.dto.OfficialAccountsBindingDto;
import com.quectel.core.module.officialaccounts.service.OfficialAccountsBindingService;
import com.quectel.core.module.thirdconfig.dto.item.WechatOfficial;
import com.quectel.sdk.officialaccounts.OfficialAccountsUtils;
import com.quectel.sys.module.sys.dto.SysTenantDto;
import com.quectel.sys.module.sys.dto.SysUserDto;
import com.quectel.sys.module.sys.service.*;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.redis.RedisUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 公众号登录相关
 */
@RestController
@RequestMapping("officialAccounts/sys")
@Tag(name = "OfficialAccountsLoginController", description = "cms公众号接口")
public class OfficialAccountsLoginController extends BaseController {

    /**
     * key prefix+type+appId+code 中间下划线隔开
     * value openId
     */
    private static final String USER_OPEN_ID_BINDING_PREFIX = CmsRedisCacheConstants.PROJECT_NAME + "USER_OPEN_ID_BINDING_PREFIX:";

    @DubboReference
    private SysUserService sysUserService;
    @DubboReference
    private SysRoleService sysRoleService;
    @DubboReference
    private SysGroupService sysGroupService;
    @DubboReference
    private SysTenantService sysTenantService;
    @DubboReference
    private SysLogService sysLogService;

    @DubboReference
    private OfficialAccountsBindingService officialAccountsBindingService;

    @Autowired
    private ApiSysLoginService apiSysLoginService;


    @Autowired
    private ThirdPlatformConfigBusiness thirdPlatformConfigBusiness;

    @PostMapping("JSAPI/login")
    @Operation(summary = "微信JSAPI登录接口,获取token,后续请求需要在请求头中加入token")
    public Response<LoginUserSession> wechatJSAPI(@RequestBody JSAPILoginVo loginVo) {

        long t1 = System.currentTimeMillis();

        logger.debug("微信用户获取openId，请求参数：code=" + JacksonUtils.toJsonString(loginVo));

        SysTenantDto sysTenantDto = sysTenantService.selectOneByCode(loginVo.getCode());
        if (sysTenantDto == null) {
            return Response.error("链接错误请检查");
        }

        String openId = null;
        if (SystemConstants.OFFICIAL_ACCOUNTS_PLATFORM_WX.equals(loginVo.getOfficialAccountsType())) {
            WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(sysTenantDto.getId());
            if (wechatOfficialConfig == null) {
                throw new CheckErrorException("公众号没有配置");
            }

            //查询配置 获取微信用户唯一id
            openId = OfficialAccountsUtils.getWxJsApiUserId(wechatOfficialConfig.getAppId(),
                    wechatOfficialConfig.getAppSecret(), loginVo.getCode());
        }
        if (openId == null) {
            return Response.error("无法获取用户在平台上的唯一值");
        }

        if (openId == null) {
            return Response.error("无法获取用户在平台上的唯一值");
        }
        //把获取到的openId绑定存入方便后期使用
        String cacheRelationKey = String.format("%s_%s_%s_%s", USER_OPEN_ID_BINDING_PREFIX, loginVo.getOfficialAccountsType(), loginVo.getAppId(), loginVo.getCode());
        RedisUtils.set(cacheRelationKey,
                openId, 10, TimeUnit.MINUTES);

        //查看是否有绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginVo.getOfficialAccountsType(),
                loginVo.getAppId(),
                openId,
                OfficialAccountsConstants.PERSON_TYPE_SYS
        );

        if (officialAccountsBindingDto == null) {
            return Response.error("用户未绑定");
        }

        SysUserDto sysUserDto = sysUserService.selectById(officialAccountsBindingDto.getPersonId());
        if (sysUserDto == null) {
            return Response.error("用户不存在");
        }

        Response<LoginUserSession> response = apiSysLoginService.buildSessionBySysUser(sysUserDto);
        if (!response.isSuccess()) {
            //登录不成功
            return response;
        }
        //如果能走到这一步说明不需要绑定操作删除相应的缓存关系
        RedisUtils.del(cacheRelationKey);


        LoginUserSession session = response.getData();
        session.setOfficialAccountsType(SystemConstants.OFFICIAL_ACCOUNTS_PLATFORM_WX);
        session.setAppId(loginVo.getAppId());
        session.setOpenId(openId);

        return Response.<LoginUserSession>ok().wrap(SessionHolder.buildRedisSession(session));
    }

    @PostMapping("bind")
    @Operation(summary = "登录成功后需要绑定")
    public Response<LoginUserSession> bind(@RequestBody JSAPILoginVo loginVo) {

        String openId = RedisUtils.get(String.format("%s_%s_%s_%s", USER_OPEN_ID_BINDING_PREFIX, loginVo.getOfficialAccountsType(), loginVo.getAppId(), loginVo.getCode()));
        if (StringUtils.isBlank(openId)) {
            return Response.ok();
        }

        //查看是否有绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginVo.getOfficialAccountsType(),
                loginVo.getAppId(),
                openId,
                OfficialAccountsConstants.PERSON_TYPE_SYS
        );
        if (officialAccountsBindingDto == null) {
            OfficialAccountsBindingDto saveObj = new OfficialAccountsBindingDto();
            saveObj.setType(loginVo.getOfficialAccountsType());
            saveObj.setAppId(loginVo.getAppId());
            saveObj.setOpenId(openId);
            saveObj.setPersonType(OfficialAccountsConstants.PERSON_TYPE_SYS);
            saveObj.setPersonId(SessionHolder.getSysUserId());
            saveObj.setCreateTime(new Date());
            officialAccountsBindingService.save(saveObj);
        } else {
            officialAccountsBindingDto.setPersonId(SessionHolder.getSysUserId());
            officialAccountsBindingService.updateById(officialAccountsBindingDto);
        }
        //session字段补充
        LoginUserSession session = SessionHolder.getSysUser();
        session.setOfficialAccountsType(loginVo.getOfficialAccountsType());
        session.setAppId(loginVo.getAppId());
        session.setOpenId(openId);
        return Response.<LoginUserSession>ok().wrap(SessionHolder.buildRedisSession(session));
    }

    @PostMapping("logout")
    @Operation(summary = "用户登录后退出")
    public Response<Object> logout() {
        LoginUserSession loginUser = SessionHolder.getSysUser();
        if (loginUser != null) {
            RedisUtils.del(CmsRedisCacheConstants.TOKEN_USER_PREFIX + loginUser.getToken());
            //解除关系
            OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                    loginUser.getOfficialAccountsType(),
                    loginUser.getAppId(),
                    loginUser.getOpenId(),
                    OfficialAccountsConstants.PERSON_TYPE_SYS
            );
            if (officialAccountsBindingDto != null) {
                officialAccountsBindingService.deleteById(officialAccountsBindingDto.getId());
            }
        }
        return Response.ok();
    }
}
